package com.my.imq.web.tools;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;

import org.springframework.util.ReflectionUtils;

import com.invient.vaadin.charts.Color.RGB;
import com.invient.vaadin.charts.Color.RGBA;
import com.invient.vaadin.charts.Gradient;
import com.invient.vaadin.charts.Gradient.LinearGradient.LinearColorStop;
import com.invient.vaadin.charts.InvientCharts;
import com.invient.vaadin.charts.InvientCharts.DateTimePoint;
import com.invient.vaadin.charts.InvientCharts.DateTimeSeries;
import com.invient.vaadin.charts.InvientCharts.SeriesType;
import com.invient.vaadin.charts.InvientChartsConfig;
import com.invient.vaadin.charts.InvientChartsConfig.AreaConfig;
import com.invient.vaadin.charts.InvientChartsConfig.AxisBase.AxisTitle;
import com.invient.vaadin.charts.InvientChartsConfig.AxisBase.NumberPlotLine;
import com.invient.vaadin.charts.InvientChartsConfig.AxisBase.NumberPlotLine.NumberValue;
import com.invient.vaadin.charts.InvientChartsConfig.AxisBase.Tick;
import com.invient.vaadin.charts.InvientChartsConfig.DashStyle;
import com.invient.vaadin.charts.InvientChartsConfig.DateTimeAxis;
import com.invient.vaadin.charts.InvientChartsConfig.GeneralChartConfig.Margin;
import com.invient.vaadin.charts.InvientChartsConfig.MarkerState;
import com.invient.vaadin.charts.InvientChartsConfig.NumberYAxis;
import com.invient.vaadin.charts.InvientChartsConfig.SeriesState;
import com.invient.vaadin.charts.InvientChartsConfig.SymbolMarker;
import com.invient.vaadin.charts.InvientChartsConfig.XAxis;
import com.invient.vaadin.charts.InvientChartsConfig.YAxis;
import com.my.imq.model.Broker;
import com.vaadin.ui.ProgressIndicator;
import com.vaadin.ui.VerticalLayout;

/**
 * Spline Chart
 * @author <a href="MABDELOUHAB">MABDELOUHAB</a>
 * created 12 févr. 2013
 * @since 
 * @version $Id$
 */
public class Chart
    extends VerticalLayout
{
    public static String AXISTITLE = "Value";

    private ProgressIndicator indicator;

    protected InvientCharts chart;

    private Map<String, DateTimeSeries> series;

    /**
     * Constructeur par defaut. 
     */
    public Chart( String title )
    {
        super();

        InvientChartsConfig chartConfig = new InvientChartsConfig();
        chartConfig.getGeneralChartConfig().setType( SeriesType.AREA );
        chartConfig.getGeneralChartConfig().setMargin( new Margin() );
        chartConfig.getGeneralChartConfig().getMargin().setRight( 10 );

        chartConfig.getTitle().setText( title );

        // Set plot options
        AreaConfig areaCfg = new AreaConfig();

        List<LinearColorStop> colorStops = new ArrayList<Gradient.LinearGradient.LinearColorStop>();
        colorStops.add( new LinearColorStop( 0, new RGB( 69, 114, 167 ) ) );
        colorStops.add( new LinearColorStop( 1, new RGBA( 2, 0, 0, 0 ) ) );
        // Fill color
        areaCfg.setFillColor( new Gradient.LinearGradient( 0, 0, 0, 300, colorStops ) );

        areaCfg.setLineWidth( 1 );
        areaCfg.setShadow( false );
        areaCfg.setHoverState( new SeriesState() );
        areaCfg.getHoverState().setLineWidth( 1 );

        SymbolMarker marker;
        areaCfg.setMarker( marker = new SymbolMarker( false ) );
        marker.setHoverState( new MarkerState() );
        marker.getHoverState().setEnabled( true );
        marker.getHoverState().setRadius( 5 );

        chartConfig.addSeriesConfig( areaCfg );

        // Area configuration
        AreaConfig serieaAreaCfg = new AreaConfig();
        serieaAreaCfg.setPointInterval( 24 * 3600 * 1000.0 );

        DateTimeAxis xAxis = new DateTimeAxis();
        xAxis.setTick( new Tick() );
        xAxis.getTick().setPixelInterval( 150 );
        LinkedHashSet<XAxis> xAxes = new LinkedHashSet<InvientChartsConfig.XAxis>();
        xAxes.add( xAxis );
        chartConfig.setXAxes( xAxes );

        NumberYAxis yAxis = new NumberYAxis();
        yAxis.setTitle( new AxisTitle( Chart.AXISTITLE ) );
        NumberPlotLine plotLine;
        yAxis.addPlotLine( plotLine = new NumberPlotLine( "LineAt0" ) );
        plotLine.setValue( new NumberValue( 0.0 ) );
        plotLine.setWidth( 1 );
        plotLine.setDashStyle( DashStyle.SHORT_DOT );
        plotLine.setColor( new RGB( 128, 128, 128 ) );
        LinkedHashSet<YAxis> yAxes = new LinkedHashSet<InvientChartsConfig.YAxis>();
        yAxes.add( yAxis );
        chartConfig.setYAxes( yAxes );

        chartConfig.getTooltip()
            .setFormatterJsFunc( "function() {" + " return '<b>'+ this.series.name +'</b><br/>'+ "
                                     + " $wnd.Highcharts.dateFormat('%Y-%m-%d %H:%M:%S', this.x) +'<br/>'+ "
                                     + " $wnd.Highcharts.numberFormat(this.y, 2);" + "}" );

        chartConfig.getLegend().setEnabled( true );

        chart = new InvientCharts( chartConfig );
        chart.setStyleName( "v-chart-min-width" );
        this.removeStyleName( "v-chart-master-detail" );
        this.removeAllComponents();
        this.addComponent( chart );

        indicator = new ProgressIndicator( 0.2f );
        indicator.setPollingInterval( 1000 );
        indicator.setStyleName( "i-progressindicator-invisible" );
        this.addComponent( indicator );
    }

    /**
     * @param listDateTimeSeries the listDateTimeSeries to set
     */
    public void addSerie( String name )
    {
        if ( this.series == null )
        {
            this.series = new HashMap<String, DateTimeSeries>();
        }
        DateTimeSeries dateTimeSerie = new DateTimeSeries( name, SeriesType.AREA, true );
        series.put( name, dateTimeSerie );
        this.chart.addSeries( dateTimeSerie );
    }

    public void populate( List<Broker> brokers )
        throws IllegalArgumentException, IllegalAccessException
    {
        LinkedHashSet<DateTimePoint> points = new LinkedHashSet<DateTimePoint>();
        if ( this.series != null )
        {

            Iterator it = series.entrySet().iterator();
            while ( it.hasNext() )
            {
                Map.Entry pairs = (Map.Entry) it.next();
                DateTimeSeries serie = (DateTimeSeries) pairs.getValue();
                Field field = ReflectionUtils.findField( Broker.class, (String) pairs.getKey() );
                field.setAccessible( true );
                for ( Broker broker : brokers )
                {
                    String val = (String) field.get( broker );
                    points.add( new DateTimePoint( serie, broker.getTime(), Double.parseDouble( val ) ) );
                }

                serie.setSeriesPoints( points );
            }

        }
    }

    /**
     * @return the series
     */
    public Map<String, DateTimeSeries> getSeries()
    {
        return series;
    }

}
